package crud.service.impl;

//JDK库

import java.sql.*;
import java.util.ArrayList;
import java.util.List;
//工具库
import cn.hutool.cache.Cache;
import cn.hutool.cache.CacheUtil;
import cn.hutool.core.util.StrUtil;


//框架库

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import crud.util.SqlUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;

//内部包
import crud.service.InterfaceService;
import crud.domain.SysInterface;


@Service
@Slf4j
public class InterfaceServiceImpl implements InterfaceService {

    @Value("${cache}")
    private boolean cache;


    static final String fullSql = " SELECT\n" +
            "        ci.id,\n" +
            "        cs.id systemId,\n" +
            "        cs.sys_code AS systemCode,\n" +
            "        cm.id AS moduleId,\n" +
            "        cm.m_code AS moduleCode,\n" +
            "        cr.res_code AS resCode,\n" +
            "        cr.res_name AS resName,\n" +
            "        ci.database_id AS databaseId,\n" +
            "        cd.sql_mode AS databaseSqlMode,\n" +
            "        cd.db_name AS databaseSchema,\n" +
            "        ci.table_name AS tableName,\n" +
            "        ci.api_type As apiType,\n" +
            "        ci.api_action_type As apiActionType,\n" +
            "        ci.api_path As apiCode,\n" +
            "        ci.api_template AS apiTemplate,\n" +
            "        ci.id_field as idField,\n" +
            "        ci.primary_fields as primaryFields,\n" +
            "        ci.required_fields as requiredFields,\n" +
            "        ci.like_fields as likeFields\n" +
            "        FROM\n" +
            "        crud_interface ci\n" +
            "        LEFT JOIN crud_system cs ON cs.id = ci.system_id\n" +
            "        LEFT JOIN crud_module cm ON cm.id = ci.module_id\n" +
            "        LEFT JOIN crud_database cd ON cd.id = ci.database_id\n" +
            "        LEFT JOIN crud_resource cr ON cr.id = ci.resource_id\n" +
            "        WHERE\n" +
            "        ci.api_status = 1 AND cs.sys_status = 1";

    static final String sql = " SELECT\n" +
            "        ci.id,\n" +
            "        cs.id systemId,\n" +
            "        cs.sys_code AS systemCode,\n" +
            "        cm.id AS moduleId,\n" +
            "        cm.m_code AS moduleCode,\n" +
            "        cr.res_code AS resCode,\n" +
            "        cr.res_name AS resName,\n" +
            "        ci.database_id AS databaseId,\n" +
            "        cd.sql_mode AS databaseSqlMode,\n" +
            "        cd.db_name AS databaseSchema,\n" +
            "        ci.table_name AS tableName,\n" +
            "        ci.api_type As apiType,\n" +
            "        ci.api_action_type As apiActionType,\n" +
            "        ci.api_path As apiCode,\n" +
            "        ci.api_template AS apiTemplate,\n" +
            "        ci.id_field as idField,\n" +
            "        ci.primary_fields as primaryFields,\n" +
            "        ci.required_fields as requiredFields,\n" +
            "        ci.like_fields as likeFields\n" +
            "        FROM\n" +
            "        crud_interface ci\n" +
            "        LEFT JOIN crud_system cs ON cs.id = ci.system_id\n" +
            "        LEFT JOIN crud_module cm ON cm.id = ci.module_id\n" +
            "        LEFT JOIN crud_database cd ON cd.id = ci.database_id\n" +
            "        LEFT JOIN crud_resource cr ON cr.id = ci.resource_id\n" +
            "        WHERE\n" +
            "        ci.api_status = 1 AND cs.sys_status = 1\n" +
            "        AND cs.sys_code = ? AND cm.m_code = ? AND cr.res_code = ? AND ci.api_path = ?";


    static Cache<String, SysInterface> apiCache = CacheUtil.newLFUCache(10000);


    private synchronized SysInterface getInterfaceFromConf(String uri) throws Exception {

        Connection dbCon = SqlUtil.getCrudDbCon();

        SysInterface sysInterface = null;
        if (cache && apiCache.isEmpty()) {
            JSONArray rows = SqlUtil.executeQuery(dbCon, fullSql);
            for (Object o : rows) {
                JSONObject row = (JSONObject) o;
                sysInterface = JSONObject.toJavaObject(row, SysInterface.class);
                apiCache.put(uri, sysInterface);
            }
        }

        if (cache && apiCache.containsKey(uri)) {
            sysInterface = apiCache.get(uri);
            return sysInterface;
        }

        List<String> uriList = StrUtil.split(uri, "/");
        String systemCode = uriList.get(1);
        String moduleCode = uriList.get(2);
        String resCode = uriList.get(3);
        String apiCode = uriList.get(4);

        List<Object> params = new ArrayList<>();
        params.add(systemCode);
        params.add(moduleCode);
        params.add(resCode);
        params.add(apiCode);
        JSONArray rows = SqlUtil.executeQuery(dbCon, sql, params);

        if (!rows.isEmpty()) {
            JSONObject row = (JSONObject) rows.get(0);
            sysInterface = JSONObject.toJavaObject(row, SysInterface.class);
            if (cache) {
                apiCache.put(uri, sysInterface);
            }
        }

        return sysInterface;
    }

    @Override
    public SysInterface getInterface(String uri) throws Exception {
        List<String> uriList = StrUtil.split(uri, "/");
        if (uriList.size() != 5) {
            throw new Exception(String.format("接口格式不合法[%s]", uri));
        }

        SysInterface sysInterface;
        try {
            sysInterface = getInterfaceFromConf(uri);
        } catch (Exception ex) {
            throw new Exception(String.format("获取接口配置失败[%s]", ex));
        }

        if (sysInterface == null) {
            throw new Exception(String.format("接口未注册[%s]", uri));
        }

        return sysInterface;
    }

}